home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / term.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  20KB  |  869 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8. /*
  9.  *
  10.  * term.c: functions for controlling the terminal
  11.  *
  12.  * primitive termcap support for Amiga and MSDOS included
  13.  *
  14.  * NOTE: padding and variable substitution is not performed,
  15.  * when compiling without TERMCAP, we use tputs() and tgoto() dummies.
  16.  */
  17.  
  18. #include "vim.h"
  19. #include "globals.h"
  20. #include "param.h"
  21. #include "proto.h"
  22. #ifdef TERMCAP
  23. # ifdef linux
  24. #  include <termcap.h>
  25. #  if 0        /* only required for old versions, it's now in termcap.h */
  26.     typedef int (*outfuntype) (int);
  27. #  endif
  28. #  define TPUTSFUNCAST (outfuntype)
  29. # else
  30. #  define TPUTSFUNCAST
  31. #  ifdef AMIGA
  32. #   include "proto/termlib.pro"
  33. #  endif
  34. # endif
  35. #endif
  36.  
  37. static void parse_builtin_tcap __ARGS((Tcarr *tc, char_u *s));
  38.  
  39. /*
  40.  * Builtin_tcaps must always contain DFLT_TCAP as the first entry!
  41.  * DFLT_TCAP is used, when no terminal is specified with -T option or $TERM.
  42.  * The entries are compact, therefore they normally are included even when
  43.  * TERMCAP is defined.
  44.  * When TERMCAP is defined, the builtin entries can be accessed with
  45.  * "builtin_amiga", "builtin_ansi", "builtin_debug", etc.
  46.  */
  47. static char_u *builtin_tcaps[] =
  48. {
  49. #ifndef NO_BUILTIN_TCAPS
  50.   (char_u *)DFLT_TCAP,        /* almost allways included */
  51. # if !defined(UNIX) && (defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS))
  52.   (char_u *)ANSI_TCAP,        /* default for unix */
  53. # endif
  54. # if !defined(AMIGA) && (defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS))
  55.   (char_u *)AMIGA_TCAP,        /* default for amiga */
  56. # endif
  57. # if !defined(MSDOS) && (defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS))
  58.   (char_u *)PCTERM_TCAP,        /* default for MSdos */
  59. # endif
  60. # if defined(MSDOS) || defined(ALL_BUILTIN_TCAPS)
  61.   (char_u *)PCANSI_TCAP,
  62. # endif
  63. # if !defined(ATARI) && defined(ALL_BUILTIN_TCAPS)
  64.   (char_u *)ATARI_TCAP,        /* default for Atari */
  65. # endif
  66. # if defined(UNIX) || defined(ALL_BUILTIN_TCAPS) || defined(SOME_BUILTIN_TCAPS)
  67.   (char_u *)XTERM_TCAP,        /* always included on unix */
  68. # endif
  69. # ifdef ALL_BUILTIN_TCAPS
  70.   (char_u *)VT52_TCAP,
  71. # endif
  72. # if defined(DEBUG) || defined(ALL_BUILTIN_TCAPS)
  73.   (char_u *)DEBUG_TCAP,        /* always included when debugging */
  74. # endif
  75. #else /* NO_BUILTIN_TCAPS */
  76.   (char_u *)DUMB_TCAP,        /* minimal termcap, used when everything else fails */
  77. #endif /* NO_BUILTIN_TCAPS */
  78.   NULL,
  79. };
  80.  
  81. /*
  82.  * Term_strings contains currently used terminal strings.
  83.  * It is initialized with the default values by parse_builtin_tcap().
  84.  * The values can be changed by setting the parameter with the same name.
  85.  */
  86. Tcarr term_strings;
  87.  
  88. /*
  89.  * Parsing of the builtin termcap entries.
  90.  * The terminal's name is not set, as this is already done in termcapinit().
  91.  * Chop builtin termcaps, string entries are already '\0' terminated.
  92.  * not yet implemented:
  93.  *   boolean entries could be empty strings;
  94.  *   numeric entries would need a flag (e.g. high bit of the skip byte),
  95.  *   so that parse_builtin_tcap can handle them.
  96.  */
  97.     static void
  98. parse_builtin_tcap(tc, s)
  99.     Tcarr *tc;
  100.     char_u *s;
  101. {
  102.     char_u **p = &tc->t_name;
  103.  
  104.     p++;
  105.     for (;;)
  106.     {
  107.         while (*s++)
  108.             ;
  109.         p += *s++;
  110.         if (!*s)
  111.             return;
  112.         *p++ = s;
  113.     }
  114. }
  115.  
  116. #ifdef TERMCAP
  117. # ifndef linux        /* included in <termlib.h> */
  118. #  ifndef AMIGA        /* included in proto/termlib.pro */
  119. int                tgetent();
  120. int                tgetnum();
  121. char            *tgetstr();
  122. int                tgetflag();
  123. int                tputs();
  124. #  endif /* AMIGA */
  125. #  ifndef hpux
  126. extern short    ospeed;
  127. #  endif
  128. # endif /* linux */
  129. # ifndef hpux
  130. char        *UP, *BC, PC;        /* should be extern, but some don't have them */
  131. # endif
  132. #endif /* TERMCAP */
  133.  
  134. #ifdef linux
  135. # define TGETSTR(s, p)    (char_u *)tgetstr((s), (char **)(p))
  136. #else
  137. # define TGETSTR(s, p)    (char_u *)tgetstr((s), (char *)(p))
  138. #endif
  139.  
  140.     void
  141. set_term(term)
  142.     char_u *term;
  143. {
  144.     char_u **p = builtin_tcaps;
  145. #ifdef TERMCAP
  146.     int builtin = 0;
  147. #endif
  148.     int width = 0, height = 0;
  149.  
  150.     if (!STRNCMP(term, "builtin_", (size_t)8))
  151.     {
  152.         term += 8;
  153. #ifdef TERMCAP
  154.         builtin = 1;
  155. #endif
  156.     }
  157. #ifdef TERMCAP
  158.     else
  159.     {
  160.         char_u            *p;
  161.         static char_u    tstrbuf[TBUFSZ];
  162.         char_u            tbuf[TBUFSZ];
  163.         char_u            *tp = tstrbuf;
  164.         int                i;
  165.  
  166.         i = tgetent(tbuf, term);
  167.         if (i == -1)
  168.         {
  169.             EMSG("Cannot open termcap file");
  170.             builtin = 1;
  171.         }
  172.         else if (i == 0)
  173.         {
  174.             EMSG("terminal entry not found");
  175.             builtin = 1;
  176.         }
  177.         else
  178.         {
  179.             clear_termparam();        /* clear old parameters */
  180.         /* output strings */
  181.             T_EL = TGETSTR("ce", &tp);
  182.             T_IL = TGETSTR("al", &tp);
  183.             T_CIL = TGETSTR("AL", &tp);
  184.             T_DL = TGETSTR("dl", &tp);
  185.             T_CDL = TGETSTR("DL", &tp);
  186.             T_CS = TGETSTR("cs", &tp);
  187.             T_ED = TGETSTR("cl", &tp);
  188.             T_CI = TGETSTR("vi", &tp);
  189.             T_CV = TGETSTR("ve", &tp);
  190.             T_CVV = TGETSTR("vs", &tp);
  191.             T_TP = TGETSTR("me", &tp);
  192.             T_TI = TGETSTR("mr", &tp);
  193.             T_TB = TGETSTR("md", &tp);
  194.             T_SE = TGETSTR("se", &tp);
  195.             T_SO = TGETSTR("so", &tp);
  196.             T_CM = TGETSTR("cm", &tp);
  197.             T_SR = TGETSTR("sr", &tp);
  198.             T_CRI = TGETSTR("RI", &tp);
  199.             T_VB = TGETSTR("vb", &tp);
  200.             T_KS = TGETSTR("ks", &tp);
  201.             T_KE = TGETSTR("ke", &tp);
  202.             T_TS = TGETSTR("ti", &tp);
  203.             T_TE = TGETSTR("te", &tp);
  204.  
  205.         /* key codes */
  206.             term_strings.t_ku = TGETSTR("ku", &tp);
  207.             term_strings.t_kd = TGETSTR("kd", &tp);
  208.             term_strings.t_kl = TGETSTR("kl", &tp);
  209.                 /* if cursor-left == backspace, ignore it (televideo 925) */
  210.             if (term_strings.t_kl != NULL && *term_strings.t_kl == Ctrl('H'))
  211.                 term_strings.t_kl = NULL;
  212.             term_strings.t_kr = TGETSTR("kr", &tp);
  213.             /* term_strings.t_sku = TGETSTR("", &tp); termcap code unknown */
  214.             /* term_strings.t_skd = TGETSTR("", &tp); termcap code unknown */
  215. #ifdef ARCHIE
  216.             /* Termcap code made up! */
  217.             term_strings.t_sku = tgetstr("su", &tp);
  218.             term_strings.t_skd = tgetstr("sd", &tp);
  219. #else
  220.             term_strings.t_sku = NULL;
  221.             term_strings.t_skd = NULL;
  222. #endif
  223.             term_strings.t_skl = TGETSTR("#4", &tp);
  224.             term_strings.t_skr = TGETSTR("%i", &tp);
  225.             term_strings.t_f1 = TGETSTR("k1", &tp);
  226.             term_strings.t_f2 = TGETSTR("k2", &tp);
  227.             term_strings.t_f3 = TGETSTR("k3", &tp);
  228.             term_strings.t_f4 = TGETSTR("k4", &tp);
  229.             term_strings.t_f5 = TGETSTR("k5", &tp);
  230.             term_strings.t_f6 = TGETSTR("k6", &tp);
  231.             term_strings.t_f7 = TGETSTR("k7", &tp);
  232.             term_strings.t_f8 = TGETSTR("k8", &tp);
  233.             term_strings.t_f9 = TGETSTR("k9", &tp);
  234.             term_strings.t_f10 = TGETSTR("k;", &tp);
  235.             term_strings.t_sf1 = TGETSTR("F1", &tp);    /* really function keys 11-20 */
  236.             term_strings.t_sf2 = TGETSTR("F2", &tp);
  237.             term_strings.t_sf3 = TGETSTR("F3", &tp);
  238.             term_strings.t_sf4 = TGETSTR("F4", &tp);
  239.             term_strings.t_sf5 = TGETSTR("F5", &tp);
  240.             term_strings.t_sf6 = TGETSTR("F6", &tp);
  241.             term_strings.t_sf7 = TGETSTR("F7", &tp);
  242.             term_strings.t_sf8 = TGETSTR("F8", &tp);
  243.             term_strings.t_sf9 = TGETSTR("F9", &tp);
  244.             term_strings.t_sf10 = TGETSTR("FA", &tp);
  245.             term_strings.t_help = TGETSTR("%1", &tp);
  246.             term_strings.t_undo = TGETSTR("&8", &tp);
  247.  
  248.             height = tgetnum("li");
  249.             width = tgetnum("co");
  250.  
  251.             T_MS = tgetflag("ms") ? (char_u *)"yes" : (char_u *)NULL;
  252.  
  253. # ifndef hpux
  254.             BC = (char *)TGETSTR("bc", &tp);
  255.             UP = (char *)TGETSTR("up", &tp);
  256.             p = TGETSTR("pc", &tp);
  257.             if (p)
  258.                 PC = *p;
  259.             ospeed = 0;
  260. # endif
  261.         }
  262.     }
  263.     if (builtin)
  264. #endif
  265.     {
  266.         while (*p && STRCMP(term, *p))
  267.             p++;
  268.         if (!*p)
  269.         {
  270.             fprintf(stderr, "'%s' not builtin. Available terminals are:\r\n", term);
  271.             for (p = builtin_tcaps; *p; p++)
  272. #ifdef TERMCAP
  273.                 fprintf(stderr, "\tbuiltin_%s\r\n", *p);
  274. #else
  275.                 fprintf(stderr, "\t%s\r\n", *p);
  276. #endif
  277.             if (!starting)        /* when user typed :set term=xxx, quit here */
  278.             {
  279.                 wait_return(TRUE);
  280.                 return;
  281.             }
  282.             sleep(2);
  283.             fprintf(stderr, "defaulting to '%s'\r\n", *builtin_tcaps);
  284.             sleep(2);
  285.             p = builtin_tcaps;
  286.             free(term_strings.t_name);
  287.             term_strings.t_name = strsave(term = *p);
  288.         }
  289.         clear_termparam();        /* clear old parameters */
  290.         parse_builtin_tcap(&term_strings, *p);
  291.     }
  292. /*
  293.  * special: There is no info in the termcap about whether the cursor positioning
  294.  * is relative to the start of the screen or to the start of the scrolling region.
  295.  * We just guess here. Only msdos pcterm is known to do it relative.
  296.  */
  297.     if (STRCMP(term, "pcterm") == 0)
  298.         T_CSC = (char_u *)"yes";
  299.     else
  300.         T_CSC = NULL;
  301.  
  302. #if defined(AMIGA) || defined(MSDOS)
  303.         /* DFLT_TCAP indicates that it is the machine console. */
  304.     if (STRCMP(term, *builtin_tcaps))
  305.         term_console = FALSE;
  306.     else
  307.     {
  308.         term_console = TRUE;
  309. # ifdef AMIGA
  310.         win_resize_on();        /* enable window resizing reports */
  311. # endif
  312.     }
  313. #endif
  314.     ttest(TRUE);
  315.         /* display initial screen after ttest() checking. jw. */
  316.     if (width <= 0 || height <= 0)
  317.     {
  318.         /* termcap failed to report size */
  319.         /* set defaults, in case mch_get_winsize also fails */
  320.         width = 80;
  321. #ifdef MSDOS
  322.         height = 25;        /* console is often 25 lines */
  323. #else
  324.         height = 24;        /* most terminals are 24 lines */
  325. #endif
  326.     }
  327.     set_winsize(width, height, FALSE);    /* may change Rows */
  328. }
  329.  
  330. #if defined(TERMCAP) && defined(UNIX)
  331. /*
  332.  * Get Columns and Rows from the termcap. Used after a window signal if the
  333.  * ioctl() fails. It doesn't make sense to call tgetent each time if the "co"
  334.  * and "li" entries never change. But this may happen on some systems.
  335.  */
  336.     void
  337. getlinecol()
  338. {
  339.     char_u            tbuf[TBUFSZ];
  340.  
  341.     if (term_strings.t_name != NULL && tgetent(tbuf, term_strings.t_name) > 0)
  342.     {
  343.         if (Columns == 0)
  344.             Columns = tgetnum("co");
  345.         if (Rows == 0)
  346.             Rows = tgetnum("li");
  347.     }
  348. }
  349. #endif
  350.  
  351. static char_u *tltoa __PARMS((unsigned long));
  352.  
  353.     static char_u *
  354. tltoa(i)
  355.     unsigned long i;
  356. {
  357.     static char_u buf[16];
  358.     char_u        *p;
  359.  
  360.     p = buf + 15;
  361.     *p = '\0';
  362.     do
  363.     {
  364.         --p;
  365.         *p = i % 10 + '0';
  366.         i /= 10;
  367.     }
  368.     while (i > 0 && p > buf);
  369.     return p;
  370. }
  371.  
  372. #ifndef TERMCAP
  373.  
  374. /*
  375.  * minimal tgoto() implementation.
  376.  * no padding and we only parse for %i %d and %+char
  377.  */
  378.  
  379.     char *
  380. tgoto(cm, x, y)
  381.     char *cm;
  382.     int x, y;
  383. {
  384.     static char buf[30];
  385.     char *p, *s, *e;
  386.  
  387.     if (!cm)
  388.         return "OOPS";
  389.     e = buf + 29;
  390.     for (s = buf; s < e && *cm; cm++)
  391.     {
  392.         if (*cm != '%')
  393.         {
  394.             *s++ = *cm;
  395.             continue;
  396.         }
  397.         switch (*++cm)
  398.         {
  399.         case 'd':
  400.             p = (char *)tltoa((unsigned long)y);
  401.             y = x;
  402.             while (*p)
  403.                 *s++ = *p++;
  404.             break;
  405.         case 'i':
  406.             x++;
  407.             y++;
  408.             break;
  409.         case '+':
  410.             *s++ = (char)(*++cm + y);
  411.             y = x;
  412.             break;
  413.         case '%':
  414.             *s++ = *cm;
  415.             break;
  416.         default:
  417.             return "OOPS";
  418.         }
  419.     }
  420.     *s = '\0';
  421.     return buf;
  422. }
  423.  
  424. #endif /* TERMCAP */
  425.  
  426. /*
  427.  * Termcapinit is called from main() to initialize the terminal.
  428.  * The optional argument is given with the -T command line option.
  429.  */
  430.     void
  431. termcapinit(term)
  432.     char_u *term;
  433. {
  434.     if (!term)
  435.         term = vimgetenv((char_u *)"TERM");
  436.     if (!term || !*term)
  437.         term = *builtin_tcaps;
  438.     term_strings.t_name = strsave(term);
  439.     set_term(term);
  440. }
  441.  
  442. /*
  443.  * the number of calls to mch_write is reduced by using the buffer "outbuf"
  444.  */
  445. #undef BSIZE            /* hpux has BSIZE in sys/param.h */
  446. #define BSIZE    2048
  447. static char_u            outbuf[BSIZE];
  448. static int                bpos = 0;        /* number of chars in outbuf */
  449.  
  450. /*
  451.  * flushbuf(): flush the output buffer
  452.  */
  453.     void
  454. flushbuf()
  455. {
  456.     if (bpos != 0)
  457.     {
  458.         mch_write(outbuf, bpos);
  459.         bpos = 0;
  460.     }
  461. }
  462.  
  463. /*
  464.  * outchar(c): put a character into the output buffer.
  465.  *               Flush it if it becomes full.
  466.  */
  467.     void
  468. outchar(c)
  469.     unsigned    c;
  470. {
  471. #ifdef UNIX
  472.     if (c == '\n')        /* turn LF into CR-LF (CRMOD does not seem to do this) */
  473.         outchar('\r');
  474. #endif
  475.  
  476.     outbuf[bpos] = c;
  477.  
  478.     if (p_nb)            /* for testing: unbuffered screen output (not for MSDOS) */
  479.         mch_write(outbuf, 1);
  480.     else
  481.         ++bpos;
  482.  
  483.     if (bpos >= BSIZE)
  484.         flushbuf();
  485. }
  486.  
  487. /*
  488.  * a never-padding outstr.
  489.  * use this whenever you don't want to run the string through tputs.
  490.  * tputs above is harmless, but tputs from the termcap library 
  491.  * is likely to strip off leading digits, that it mistakes for padding
  492.  * information. (jw)
  493.  */
  494.     void
  495. outstrn(s)
  496.     char_u *s;
  497. {
  498.     if (bpos > BSIZE - 20)        /* avoid terminal strings being split up */
  499.         flushbuf();
  500.     while (*s)
  501.         outchar(*s++);
  502. }
  503.  
  504. /*
  505.  * outstr(s): put a string character at a time into the output buffer.
  506.  * If TERMCAP is defined use the termcap parser. (jw)
  507.  */
  508.     void
  509. outstr(s)
  510.     register char_u             *s;
  511. {
  512.     if (bpos > BSIZE - 20)        /* avoid terminal strings being split up */
  513.         flushbuf();
  514.     if (s)
  515. #ifdef TERMCAP
  516.         tputs(s, 1, TPUTSFUNCAST outchar);
  517. #else
  518.         while (*s)
  519.             outchar(*s++);
  520. #endif
  521. }
  522.  
  523. /* 
  524.  * cursor positioning using termcap parser. (jw)
  525.  */
  526.     void
  527. windgoto(row, col)
  528.     int        row;
  529.     int        col;
  530. {
  531.     OUTSTR(tgoto((char *)T_CM, col, row));
  532. }
  533.  
  534. /*
  535.  * Set cursor to current position.
  536.  * Should be optimized for minimal terminal output.
  537.  */
  538.  
  539.     void
  540. setcursor()
  541. {
  542.     if (!RedrawingDisabled)
  543.         windgoto(curwin->w_winpos + curwin->w_row, curwin->w_col);
  544. }
  545.  
  546.     void
  547. ttest(pairs)
  548.     int    pairs;
  549. {
  550.     char buf[70];
  551.     char *s = "terminal capability %s required.\n";
  552.     char *t = NULL;
  553.  
  554.   /* hard requirements */
  555.     if (!T_ED || !*T_ED)    /* erase display */
  556.         t = "cl";
  557.     if (!T_CM || !*T_CM)    /* cursor motion */
  558.         t = "cm";
  559.  
  560.     if (t)
  561.     {
  562.         sprintf(buf, s, t);
  563.         EMSG(buf);
  564.     }
  565.  
  566. /*
  567.  * if "cs" defined, use a scroll region, it's faster.
  568.  */
  569.     if (T_CS && *T_CS != NUL)
  570.         scroll_region = TRUE;
  571.     else
  572.         scroll_region = FALSE;
  573.  
  574.     if (pairs)
  575.     {
  576.       /* optional pairs */
  577.             /* TP goes to normal mode for TI (invert) and TB (bold) */
  578.         if ((!T_TP || !*T_TP))
  579.             T_TP = T_TI = T_TB = NULL;
  580.         if ((!T_SO || !*T_SO) ^ (!T_SE || !*T_SE))
  581.             T_SO = T_SE = NULL;
  582.             /* T_CV is needed even though T_CI is not defined */
  583.         if ((!T_CV || !*T_CV))
  584.             T_CI = NULL;
  585.             /* if 'mr' or 'me' is not defined use 'so' and 'se' */
  586.         if (T_TP == NULL || *T_TP == NUL)
  587.         {
  588.             T_TP = T_SE;
  589.             T_TI = T_SO;
  590.             T_TB = T_SO;
  591.         }
  592.             /* if 'so' or 'se' is not defined use 'mr' and 'me' */
  593.         if (T_SO == NULL || *T_SO == NUL)
  594.         {
  595.             T_SE = T_TP;
  596.             if (T_TI == NULL)
  597.                 T_SO = T_TB;
  598.             else
  599.                 T_SO = T_TI;
  600.         }
  601.     }
  602. }
  603.  
  604. /*
  605.  * inchar() - get one character from
  606.  *        1. a scriptfile
  607.  *        2. the keyboard
  608.  *
  609.  *  As much characters as we can get (upto 'maxlen') are put in buf and
  610.  *  NUL terminated (buffer length must be 'maxlen' + 1).
  611.  *
  612.  *    If we got an interrupt all input is read until none is available.
  613.  *
  614.  *  If time == 0  there is no waiting for the char.
  615.  *  If time == n  we wait for n msec for a character to arrive.
  616.  *  If time == -1 we wait forever for a character to arrive.
  617.  *
  618.  *  Return the number of obtained characters.
  619.  */
  620.  
  621.     int
  622. inchar(buf, maxlen, time)
  623.     char_u    *buf;
  624.     int        maxlen;
  625.     int        time;                        /* milli seconds */
  626. {
  627.     int                len;
  628.     int                retesc = FALSE;        /* return ESC with gotint */
  629.     register int     c;
  630.     register int    i;
  631.  
  632.     if (time == -1 || time > 100)    /* flush output before waiting */
  633.     {
  634.         cursor_on();
  635.         flushbuf();
  636.     }
  637.     did_outofmem_msg = FALSE;    /* display out of memory message (again) */
  638.  
  639. /*
  640.  * first try script file
  641.  *    If interrupted: Stop reading script files.
  642.  */
  643. retry:
  644.     if (scriptin[curscript] != NULL)
  645.     {
  646.         if (got_int || (c = getc(scriptin[curscript])) < 0)    /* reached EOF */
  647.         {
  648.                 /* when reading script file is interrupted, return an ESC to
  649.                                     get back to normal mode */
  650.             if (got_int)
  651.                 retesc = TRUE;
  652.             fclose(scriptin[curscript]);
  653.             scriptin[curscript] = NULL;
  654.             if (curscript > 0)
  655.                 --curscript;
  656.             goto retry;        /* may read other script if this one was nested */
  657.         }
  658.         if (c == 0)
  659.             c = K_ZERO;        /* replace ^@ with special code */
  660.         *buf++ = c;
  661.         *buf = NUL;
  662.         return 1;
  663.     }
  664.  
  665. /*
  666.  * If we got an interrupt, skip all previously typed characters and
  667.  * return TRUE if quit reading script file.
  668.  */
  669.     if (got_int)            /* skip typed characters */
  670.     {
  671.         while (GetChars(buf, maxlen, T_PEEK))
  672.             ;
  673.         return retesc;
  674.     }
  675.     len = GetChars(buf, maxlen, time);
  676.  
  677.     for (i = len; --i >= 0; ++buf)
  678.         if (*buf == 0)
  679.             *(char_u *)buf = K_ZERO;        /* replace ^@ with special code */
  680.     *buf = NUL;                                /* add trailing NUL */
  681.     return len;
  682. }
  683.  
  684. /*
  685.  * Check if buf[] begins with a terminal key code.
  686.  * Return 0 for no match, -1 for partial match, > 0 for full match.
  687.  * With a match the replacement code is put in buf[0], the match is
  688.  * removed and the number characters in buf is returned.
  689.  *
  690.  * Note: should always be called with buf == typestr!
  691.  */
  692.     int
  693. check_termcode(buf)
  694.     char_u    *buf;
  695. {
  696.     char_u     **p;
  697.     int        slen;
  698.     int        len;
  699.  
  700.     len = STRLEN(buf);
  701.     for (p = (char_u **)&term_strings.t_ku; p != (char_u **)&term_strings.t_undo + 1; ++p)
  702.     {
  703.         if (*p == NULL || (slen = STRLEN(*p)) == 0)        /* empty entry */
  704.             continue;
  705.         if (STRNCMP(*p, buf, (size_t)(slen > len ? len : slen)) == 0)
  706.         {
  707.             if (len >= slen)        /* got the complete sequence */
  708.             {
  709.                 len -= slen;
  710.                     /* remove matched chars, taking care of noremap */
  711.                 del_typestr(slen - 1);
  712.                     /* this relies on the Key numbers to be consecutive! */
  713.                 buf[0] = K_UARROW + (p - (char_u **)&term_strings.t_ku);
  714.                 return (len + 1);
  715.             }
  716.             return -1;                /* got a partial sequence */
  717.         }
  718.     }
  719.     return 0;                        /* no match found */
  720. }
  721.  
  722. /*
  723.  * outnum - output a (big) number fast
  724.  */
  725.     void
  726. outnum(n)
  727.     register long n;
  728. {
  729.     OUTSTRN(tltoa((unsigned long)n));
  730. }
  731.  
  732.     void
  733. check_winsize()
  734. {
  735.     if (Columns < MIN_COLUMNS)
  736.         Columns = MIN_COLUMNS;
  737.     else if (Columns > MAX_COLUMNS)
  738.         Columns = MAX_COLUMNS;
  739.     if (Rows < MIN_ROWS + 1)    /* need room for one window and command line */
  740.         Rows = MIN_ROWS + 1;
  741.     screen_new_rows();            /* may need to update window sizes */
  742. }
  743.  
  744. /*
  745.  * set window size
  746.  * If 'mustset' is TRUE, we must set Rows and Columns, do not get real
  747.  * window size (this is used for the :win command).
  748.  * If 'mustset' is FALSE, we may try to get the real window size and if
  749.  * it fails use 'width' and 'height'.
  750.  */
  751.     void
  752. set_winsize(width, height, mustset)
  753.     int        width, height;
  754.     int        mustset;
  755. {
  756.     register int         tmp;
  757.  
  758.     if (width < 0 || height < 0)    /* just checking... */
  759.         return;
  760.  
  761.     if (State == HITRETURN || State == SETWSIZE)    /* postpone the resizing */
  762.     {
  763.         State = SETWSIZE;
  764.         return;
  765.     }
  766.     screenclear();
  767. #ifdef AMIGA
  768.     flushbuf();         /* must do this before mch_get_winsize for some obscure reason */
  769. #endif /* AMIGA */
  770.     if (mustset || mch_get_winsize() == FAIL)
  771.     {
  772.         Rows = height;
  773.         Columns = width;
  774.         check_winsize();        /* always check, to get p_scroll right */
  775.         mch_set_winsize();
  776.     }
  777.     else
  778.         check_winsize();        /* always check, to get p_scroll right */
  779.     if (State == HELP)
  780.         (void)redrawhelp();
  781.     else if (!starting)
  782.     {
  783.         tmp = RedrawingDisabled;
  784.         RedrawingDisabled = FALSE;
  785.         comp_Botline_all();
  786.         updateScreen(CURSUPD);
  787.         RedrawingDisabled = tmp;
  788.         if (State == CMDLINE)
  789.             redrawcmdline();
  790.         else
  791.             setcursor();
  792.     }
  793.     flushbuf();
  794. }
  795.  
  796.     void
  797. settmode(raw)
  798.     int     raw;
  799. {
  800.     static int        oldraw = FALSE;
  801.  
  802.     if (oldraw == raw)        /* skip if already in desired mode */
  803.         return;
  804.     oldraw = raw;
  805.  
  806.     mch_settmode(raw);    /* machine specific function */
  807. }
  808.  
  809.     void
  810. starttermcap()
  811. {
  812.     outstr(T_TS);    /* start termcap mode */
  813.     outstr(T_KS);    /* start "keypad transmit" mode */
  814.     flushbuf();
  815.     termcap_active = TRUE;
  816. }
  817.  
  818.     void
  819. stoptermcap()
  820. {
  821.     outstr(T_KE);    /* stop "keypad transmit" mode */
  822.     flushbuf();
  823.     termcap_active = FALSE;
  824.     cursor_on();    /* just in case it is still off */
  825.     outstr(T_TE);    /* stop termcap mode */
  826. }
  827.  
  828. /*
  829.  * enable cursor, unless in Visual mode or no inversion possible
  830.  */
  831. static int cursor_is_off = FALSE;
  832.  
  833.     void
  834. cursor_on()
  835. {
  836.     if (cursor_is_off && (!VIsual.lnum || highlight == NULL))
  837.     {
  838.         outstr(T_CV);
  839.         cursor_is_off = FALSE;
  840.     }
  841. }
  842.  
  843.     void
  844. cursor_off()
  845. {
  846.     if (!cursor_is_off)
  847.         outstr(T_CI);            /* disable cursor */
  848.     cursor_is_off = TRUE;
  849. }
  850.  
  851. /*
  852.  * set scrolling region for window 'wp'
  853.  */
  854.     void
  855. scroll_region_set(wp)
  856.     WIN        *wp;
  857. {
  858.     OUTSTR(tgoto((char *)T_CS, wp->w_winpos + wp->w_height - 1, wp->w_winpos));
  859. }
  860.  
  861. /*
  862.  * reset scrolling region to the whole screen
  863.  */
  864.     void
  865. scroll_region_reset()
  866. {
  867.     OUTSTR(tgoto((char *)T_CS, (int)Rows - 1, 0));
  868. }
  869.